////////////////////////////////////////////////////////////////////////////////
/// @file    rpc.h
/// @version 1.0
/// @date    2021-06-28
/// @author  黄晶(kayven@outlook.com)
////////////////////////////////////////////////////////////////////////////////
#ifndef __SORAKA_C_RPC_H__
#define __SORAKA_C_RPC_H__

#include <stdint.h>

////////////////////////////////////////////////////////////////////////////////
#if (defined(_WIN32   ) || defined(_WIN64 ))
#if defined (__cplusplus)
#define STK_C_EXPORT extern "C" __declspec(dllexport)
#define STK_C_IMPORT extern "C" __declspec(dllimport)
#else
#define STK_C_EXPORT __declspec(dllexport)
#define STK_C_IMPORT __declspec(dllimport)
#endif
#endif

#if (defined(__linux__) || defined(__linux))
#if defined (__cplusplus)
#define STK_C_EXPORT extern "C"
#define STK_C_IMPORT extern "C"
#else
#define STK_C_EXPORT
#define STK_C_IMPORT
#endif
#endif

#if defined(LIBSORAKA)
#define STK_C_API STK_C_EXPORT
#else
#define STK_C_API STK_C_IMPORT
#endif

////////////////////////////////////////////////////////////////////////////////
#define SRPC_USERRET_START 0xA0000000 //自定义状态码可用数字最小值
#define SRPC_USERRET_END   0xAFFFFFFF //自定义状态码可用数字最大值

/// 预定义的状态码
#define SRPC_SOK           0x00000000 //成功, 返回真
#define SRPC_SFALSE        0x00000001 //成功, 返回假

#define SRPC_EUNKNOWN      0x80000000 //未知错误
#define SRPC_ENOTEXIST     0x80000001 //目标不存在
#define SRPC_EINTR         0x80000002 //操作被系统调用中断
#define SRPC_EIO           0x80000003 //I/O错误
#define SRPC_EACCESS       0x80000004 //访问被拒绝
#define SRPC_EALREADY      0x80000005 //操作进行中
#define SRPC_EBUSY         0x80000006 //设备/资源忙碌（被独占)
#define SRPC_EEXIST        0x80000007 //目标已存在
#define SRPC_ENETWORK      0x80000008 //网络错误
#define SRPC_EINVAL        0x80000009 //无效的类型
#define SRPC_EBADREQUEST   0x8000000A //无效的请求
#define SRPC_ENODATA       0x8000000B //没有可用的数据
#define SRPC_ETIMEOUT      0x8000000C //超时
#define SRPC_EBADMSG       0x8000000D //错误/无效的消息
#define SRPC_EOVERFLOW     0x8000000E //溢出
#define SRPC_EUSERS        0x8000000F //用户数量过多
#define SRPC_EMSGSIZE      0x80000010 //错误的消息长度
#define SRPC_ECONNRESET    0x80000011 //连接已断开
#define SRPC_ECANCELED     0x80000012 //操作被取消
#define SRPC_EBADMUTEX     0x80000013 //错误的锁定/解锁动作
#define SRPC_ENOTSUP       0x80000014 //不支持的操作
#define SRPC_ENOTIMPL      0x80000015 //未实现的操作
#define SRPC_EISDIR        0x80000016 //目标是个目录
#define SRPC_EUNREADY      0x80000017 //目标是个目录#define
#define SRPC_ESSL          0x80000100 //SSL错误
#define SRPC_ESSLRESET     0x80000101 //SSL协议断开(对端发送closure alert)
#define SRPC_ESQLDB        0x80000200 //数据库错误
#define SRPC_ESOCKCLOSED   0x80000201 //套接字对象已被关闭

////////////////////////////////////////////////////////////////////////////////
typedef void   * SRPC_DATABUF;
typedef uint32_t SRPC_RESULT;
typedef void   * SRPC_DEALER;

////////////////////////////////////////////////////////////////////////////////
/// 创建SRPC_DATABUF对象
/// @return 成功返回已创建的SRPC_DATABUF对象指针，失败返回NULL
STK_C_API SRPC_DATABUF
srpc_databuf_create ();

/// 销毁SRPC_DATABUF对象并释放与之关联的内存资源
/// @param  dbuf 已创建的SRPC_DATABUF对象
STK_C_API void
srpc_databuf_delete (SRPC_DATABUF dbuf);

/// 清空SRPC_DATABUF对象中存储的所有数据
/// @param  dbuf 已创建的SRPC_DATABUF对象
STK_C_API void
srpc_databuf_clear  (SRPC_DATABUF dbuf);

/// 向SRPC_DATABUF对象写入数据，此动作将会覆盖SRPC_DATABUF中的原有数据
/// @param  dbuf 已创建的缓冲区对象
/// @param  data 用于存储待写入数据的缓冲区指针
/// @param  size 用于存储待写入数据的缓冲区长度
/// @return 实际写入SRPC_DATABUF对象的数据长度
STK_C_API int32_t
srpc_databuf_assign (SRPC_DATABUF dbuf,
                     const void * data,
                     uint32_t     size);

/// 判断dbuf对象中是否由可读取的数据
/// @return 如果dbuf对象中没有可读取的数据，返回1，否则返回0
STK_C_API int32_t
sprc_databuf_empty  (SRPC_DATABUF dbuf);

/// 获取SRPC_DATABUF对象的数据缓冲区指针
/// @param  dbuf 已创建的缓冲区对象
/// @return 数据缓冲区指针
STK_C_API void *
srpc_databuf_data   (SRPC_DATABUF dbuf);

/// 获取SRPC_DATABUF对象中保存的数据长度（字节）
/// @param  dbuf 已创建的缓冲区对象
/// @return 数据长度（字节）
STK_C_API uint32_t
srpc_databuf_size   (SRPC_DATABUF dbuf);

////////////////////////////////////////////////////////////////////////////////
/// 判断sret指定的状态码是否代表操作失败
/// @param  sret rpc操作返回值
/// @return 如果sret代表操作失败，返回1，否则返回0
STK_C_API int
srpc_result_failed   (SRPC_RESULT  sret);

/// 判断sret指定的状态码是否代表操作成功
/// @param  sret rpc操作返回值
/// @return 如果sret代表操作成功，返回1，否则返回0
STK_C_API int
srpc_result_succeeded(SRPC_RESULT  sret);

/// 获取sret指定的状态码代表的具体信息
/// @param  sret rpc操作返回值
/// @param  dbuf 用于存储rpc操作返回值所代表的具体信息的缓冲区
STK_C_API void
srpc_result_string   (SRPC_RESULT  sret,
                      SRPC_DATABUF dbuf);

////////////////////////////////////////////////////////////////////////////////
/// 当rpc终端接受到来自消息网络中的rpc消息时，调用此回调函数
/// @param  msgType 消息类型 1="通知" 2="请求"
/// @param  service 与消息关联的服务名称
/// @param  routine 与消息关联的方法名称
/// @param  payload 消息载荷（JSON字符串), 可能为NULL（消息没有载荷）
/// @param  sender  消息的发送者编号
/// @param  target  消息的接受者编号（可能为NULL）
/// @param  peerIP  消息发送者的IP地址
/// @param  retdata 仅当消息类型为”请求“时有效，用于存储应答消息载荷
///                 的缓冲区, 应答消息载荷必须为合法的JSON字符串
/// @param  userptr 创建消息终端时传入的用户自定义指针
/// @return 此消息的处理结果（状态码）
///
/// @attention
/// 1. 回调函数返回值仅当消息类型(msgType)为“请求”时生效，用于标识请
///    求的执行结果: 小于0x80000000表示请求执行成功, 否则表示请求执行
///    失败
/// 2. 如果请求执行失败，回调函数应该在retdata参数中存储具体的失败原
///    因（JSON编码的字符串)
typedef SRPC_RESULT
(*srpc_message_proc)(int          msgType,
                     const char * service,
                     const char * routine,
                     const char * payload,
                     const char * sender ,
                     const char * target ,
                     const char * peerIP ,
                     SRPC_DATABUF retdata,
                     const void * userptr);

/// 当消息终端成功连接到引擎时，调用此回调函数
/// @param  userptr 创建消息终端时传入的用户自定义指针
typedef void
(*srpc_connready_cb)(const char * jsonstr, const void * userptr);
/// 当消息终端从引擎断开时，调用此回调函数
/// @param  userptr 创建消息终端时传入的用户自定义指针
typedef void
(*srpc_connreset_cb)(uint32_t     retcode, const void * userptr);

////////////////////////////////////////////////////////////////////////////////
STK_C_API SRPC_DEALER
srpc_dealer_create(srpc_message_proc msgproc,
                   srpc_connready_cb onready,
                   srpc_connreset_cb onreset,
                   const void *      userptr);
STK_C_API void
srpc_dealer_delete(SRPC_DEALER       dealer );

////////////////////////////////////////////////////////////////////////////////
STK_C_API SRPC_RESULT
srpc_add_service  (SRPC_DEALER  dealer ,
                   const char * name   ,
                   const char * desc   ,
                   const char * defs   ,
                   const char * rtns   );
STK_C_API SRPC_RESULT
srpc_get_property (SRPC_DEALER  dealer ,
                   const char * path   ,
                   SRPC_DATABUF dbuf   );
STK_C_API SRPC_RESULT
srpc_get_proplist (void       * dealer ,
                   SRPC_DATABUF dbuf   );
STK_C_API SRPC_RESULT
srpc_set_property (SRPC_DEALER  dealer ,
                   const char * path   ,
                   const char * data   );

////////////////////////////////////////////////////////////////////////////////
STK_C_API SRPC_RESULT
srpc_dealer_start (SRPC_DEALER  dealer ,
                   char       * addr   ,
                   int          port   );
STK_C_API void
srpc_dealer_stop  (SRPC_DEALER  dealer );

////////////////////////////////////////////////////////////////////////////////
STK_C_API SRPC_RESULT
srpc_run_routine  (SRPC_DEALER  dealer ,
                   const char * service,
                   const char * routine,
                   const char * target ,
                   const char * payload,
                   SRPC_DATABUF retdata,
                   int          timeout);
STK_C_API SRPC_RESULT
srpc_post_notice  (SRPC_DEALER  dealer ,
                   const char * service,
                   const char * routine,
                   const char * target ,
                   const char * payload);

////////////////////////////////////////////////////////////////////////////////
#endif//__SORAKA_C_RPC_H__
